<?php

namespace App\Http\Controllers\PartnerApi;

use Alipay\EasySDK\Kernel\Config;
use Alipay\EasySDK\Kernel\Factory;
use App\Enums\AssetSourceType;
use App\Enums\AssetStatus;
use App\Enums\ProductType;
use App\Exceptions\ApiException;
use App\Http\Controllers\Controller;
use App\Jobs\TransferJob;
use App\Models\Asset;
use App\Models\FrontendUser;
use App\Models\Product;
use App\Models\ProductConfig;
use App\Models\TransferRecord;
use Illuminate\Contracts\Cache\LockTimeoutException;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;

class XmetaController extends Controller
{
    private $pub_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApRJ2xuAK8EZJ+itc8kzLmBy8lw5Et3tTVinlEdimiv5O9qRCQlns9Q6mSaWfi5pTY+fDCngkI4Sg0nG6etuNzN0elAovGF06pIaBY3E/UfW3uTYmHO4faBO/t3wXfcpvbJiuMG3g+Po6y2/LPduKJMfIooL+lP89uP/LIK8Qd250rF/uRg4eBIMZWxGiYwRrDkFwn8hh04xz+u8qcnlh8Jg7b13ABgyO1GomkXkApx1SWgFmXGJ8QeuKHnfVXVe2en5KVO+fVJaz5SY5CL4zU8zThig4soihF9yUfQ1q/R8c11tjv69DJxiDTh2ZG9zgLSGahLEI30UpMBf66FIIIwIDAQAB';

    private $pra_secret = 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQClEnbG4ArwRkn6K1zyTMuYHLyXDkS3e1NWKeUR2KaK/k72pEJCWez1DqZJpZ+LmlNj58MKeCQjhKDScbp6243M3R6UCi8YXTqkhoFjcT9R9be5NiYc7h9oE7+3fBd9ym9smK4wbeD4+jrLb8s924okx8iigv6U/z24/8sgrxB3bnSsX+5GDh4EgxlbEaJjBGsOQXCfyGHTjHP67ypyeWHwmDtvXcAGDI7UaiaReQCnHVJaAWZcYnxB64oed9VdV7Z6fkpU759UlrPlJjkIvjNTzNOGKDiyiKEX3JR9DWr9HxzXW2O/r0MnGINOHZkb3OAtIZqEsQjfRSkwF/roUggjAgMBAAECggEAJA+ljQqyuQzR6moAsxodvAxDEsjWMDMr4H3kggKPV3v46h62LuKQRnS91QbulMPRBdlCnY3jbzLxIygfMem2z5Nas8KJyUvMnNaZe4zo5VHFoht3Ngi7KbRuxHnCdAN+Vf4Ax6mpZRrdL0Yr40aLpj9S0FXHoesko76VtH0qHrzTB5OYayRakzHnyRMiDWRjeU2e4MHinvpeSsR/SOOdgkySJtsI+PEUcrr2nB4WyesBqhQDA1V4wHuA3ai9UPFS+TFU9/LssLXNT5AzzB1Pw43MIN9Irgev9qP4Kgfu1h0+eFT0DTbB8p/lS/7y5uDb/HVVt3n4Gx6GlQYuBoRg0QKBgQDptRZH3iUF3HRLcDuLczfJSqovdHetSiXoclmc7MaUknYSLH92T4jXlwHzt1thjkIyRveiaoeVm9TxN4k+VM+Tqi111dbBND1HV8SF3nKqnYuF8h+pYk/2Gv27n7zGQ2LGPmOGEoevSk0Sg8LgxaPNUu++gXDqxmhs5r4PlNKe6QKBgQC00V5/ybkJJQcCOBnR6EN8/RgMCdi3z7VOKf+RQKBlTYC5keFiaCRQhJC/DeLZTJItziq8bbmRzhVJJo8f5iKufVfatsetXzERDKqKOvVC2pjII7LY2gW+T6RhWVW0w4hwCBujfTgvnZtJ9IfoIqirntxCvdMkLM5UMTv3y2Y/KwKBgCPVyYnRjTm92PMsTWUPkLFDyp6mLCedI/zlc8o1ICnt3z7gJdc9UM1F8V2ucsudpZbR/OyhixKsp1UpX9j35jBNOtVDqb9MRE0pLxAb0NdKevdZ7fLqCTrCXr+jOa3o7T9al6YaN0XwjarWG06d34T/P5WlgWvualqwctouxrDpAoGBAIr19MgEgV3TxQUhlEZLV8Jwx9BIqPLqgA3oHO7GWf5Ah9MVl78HBhGTL6KEy3fwbs8hCJrzQJAbbyReq9P6C2FKFwCRQ/erlovhzhaZpO+SC6SUOtiJBazyjAP8oe9f7jUbJhKJI2sEltlJQkFWkYYDeocYV3IPtSnjBJE1EgktAoGBAJiSqa0F/8PQ/jGJV2bmTa8GwungAgfV3qmZthwNYKKz3v/CtFaKkWjUjwMdZQI/Oq1nFqvYjVefemDcRNM32QXpnMeHOZ8U57ASiMq5BqF2TXMu+4Ian5NOWTnhkSqxmB8qbXxMiqHJ2Yyvx5AxCJx21tubfGQE4Yw6LYVjiQCG';

    private $xmeta_pub_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArXv6xay3x2+qKNrlcicBysGb4qYHo5UM9farKvTnGSawMpQ2U5B2IfDfoPjVDWNZ86j2usjqFbWdQh+3HhbTHPkFdPkkYUdz5Z4sHKe5sdOee4FVjQX6rWV1oUE/EgLM37zVWtuLbuI8vED82F5f6yVz9e78zoiiRnRGJgoCrmcwUpGDGxL8hFIN6v2OLlqhmhpbvu6m3FYUTojryn4sZw4Dbrextvppk9WDvpXwtjjL9FkvIj4kWK/XEnMtKlBmgMZ0HIEhPZ5JC9E7hea2PKEbfFlLlsban3UXSm0Qm3Ffc7mrm8alJeI2IvMLQIdkG1gTz/WvGYDNevttFePCAwIDAQAB';

    private $app_id = '77a9d3fe60fc46e39adc72eb7f4d8463';

    private $aeskey = 'Nc3OPS3qFQ+ctozs2zlMsA==';

    private $methods = [
        'xmeta.mall.user.verify' => 'phone',
        'xmeta.mall.goods.list' => 'goodsList',
        'xmeta.mall.goods.verify' => 'goodsVery',
        'xmeta.mall.goods.transfer' => 'goodsTransfer',
        'xmeta.mall.goods.transfer.confirm' => 'goodsTransferConfirm',
        'xmeta.mall.buyer.receive.verify' => 'receiveVerify',
        'xmeta.mall.goods.lock' => 'goodsLock',
        'xmeta.mall.archive.goodsCount' => 'goodsCount',
    ];

    private $method = '';

    /**
     * 统一入口.
     *
     * @param \Request $request
     *
     * @return mixed
     */
    public function handle(Request $request)
    {
        $this->method = $request->all()['method'];
        $func = $this->methods[$this->method];
        Factory::setOptions($this->getOptions());

        return $this->{$func}($request->all());
    }

    /**
     * 验证用户手机号.
     *
     * @param mixed $request
     */
    public function phone($request)
    {
        $param = $this->getParam($request['objEncrypt']);

        if (empty($param['phone'])) {
            return $this->failResponse(50200, '缺少必要参数');
        }

        $user = FrontendUser::where('mobile', $param['phone'])
            ->where('agent_id', $request['agent_id'])
            ->first();

        if (!empty($user)) {
            return $this->successResponse(['walletHash' => $user->wallet_address, 'userId' => $user->id], $request['method']);
        }

        return $this->failResponse(60100, '未找到用户');
    }

    /**
     * XMeta向一级平台发起买家接收地址校验.
     *
     * @param mixed $request
     */
    public function receiveVerify($request)
    {
        $param = $this->getParam($request['objEncrypt']);

        $user = FrontendUser::where('wallet_address', $param['walletHash'])
            ->where('agent_id', $request['agent_id'])
            ->first();

        if (!empty($user)) {
            return $this->successResponse(['status' => 1], $request['method']);
        }

        return $this->failResponse(60100, '未找到用户');
    }

    /**
     * 获取用户藏品列表.
     *
     * @param $request
     *
     * @return array
     */
    public function goodsList($request)
    {
        $param = $this->getParam($request['objEncrypt']);
        $agentId = $request['agent_id'];
        $page = $param['page'] ?? 0;
        $limit = $param['pageSize'] ?? 10;
        $keywords = $param['keyword'] ?? '';

        if (empty($param['phone']) || empty($param['walletHash'])) {
            return $this->failResponse(50200, '缺少必要参数');
        }

        $user = FrontendUser::where('agent_id', $agentId)->where('mobile', $param['phone'])->first();

        if (empty($user)) {
            return $this->failResponse(60100, '未找到用户');
        }

        $query = $this->getMyAssetQuery($user);

        $total = Asset::where('user_id', $user->id)
            ->where('asset_status', AssetStatus::HOLD)
            ->leftJoin('products', 'assets.contract_address', '=', 'products.contract_address')
            ->when(!empty($keywords), function ($q) use ($keywords) {
                return $q->where('products.name', 'like', '%' . $keywords . '%');
            })
            ->when(!empty($param['archiveId']), function ($q) use ($param) {
                return $q->where('products.id', $param['archiveId']);
            })
            ->select('assets.*', 'products.agent_id', 'products.id as p_id', 'products.name', 'products.logo_url', 'products.contract_address')
            ->orderByDesc('id')
            ->where('products.agent_id', $agentId)
            ->count();

        $assetProducts = $query
            ->leftJoin('products', 'assets.contract_address', '=', 'products.contract_address')
            ->when(!empty($keywords), function ($q) use ($keywords) {
                return $q->where('products.name', 'like', '%' . $keywords . '%');
            })
            ->when(!empty($param['archiveId']), function ($q) use ($param) {
                return $q->where('products.id', $param['archiveId']);
            })
            ->select('assets.*', 'products.id as p_id', 'products.agent_id', 'products.name', 'products.logo_url', 'products.contract_address')
            ->orderByDesc('id')
            ->where('products.agent_id', $agentId)
            ->offset(($page - 1) * $limit)
            ->limit($limit)
            ->get();

        $list = [];
        foreach ($assetProducts as $item) {
            $list[] = [
                'goodsImage' => $item->logo_url,
                'archiveId' => $item->p_id,
                'goodsNo' => $item->id,
                'goodsId' => $item->id,
                'goodsName' => $item->name,
                'goodsHash' => $item->trans_hash,
                'goodsContract' => $item->token_id,
                'goodsDescription' => $item->description ?? '',
                'canTransfer' => '',
            ];
        }

        return $this->successResponse(['goodsList' => $list, 'total' => $total], $request['method']);
    }

    /**
     * 验证藏品
     *
     * @param $request
     *
     * @return array
     */
    public function goodsVery($request)
    {
        $param = $this->getParam($request['objEncrypt']);

        $agentId = $request['agent_id'];

        $goodsIds = array_column($param['goodsList'], 'goodsId');

        $user = FrontendUser::where('agent_id', $agentId)
            ->where('mobile', $param['phone'])
            ->where('wallet_address', $param['walletHash'])
            ->first();

        $assets = Asset::whereIn('id', $goodsIds)
            ->where('user_id', $user->id)->get()->toArray();

        $assets = array_column($assets, '', 'id');

        $list = [];
        foreach ($param['goodsList'] as $k => $v) {
            $status = 1;
            if (!empty($assets[$v['goodsId']])) {
                $status = 0;
            }
            $list[] = [
                'goodsId' => $v['goodsId'],
                'goodsStatus' => $status,
            ];
        }

        return $this->successResponse($list, $request['method']);
    }

    /**
     * 转赠.
     *
     * @param mixed $request
     */
    public function goodsTransfer($request)
    {
        $param = $this->getParam($request['objEncrypt']);
        $agentId = $request['agent_id'];

        $user = FrontendUser::query()
            ->where('mobile', $param['sourcePhone'])
            ->where('agent_id', $agentId)
            ->first();
        if (!$user) {
            return $this->failResponse(60100, '未找到用户');
        }

        /** @var FrontendUser $receiveUser */
        $receiveUser = FrontendUser::query()
            ->where('mobile', $param['targetPhone'])
            ->where('agent_id', $agentId)
            ->first();
        if (!$receiveUser) {
            return $this->failResponse(60100, '未找到接收方用户');
        }

        $result = [];
        foreach ($param['goodsList'] as $good) {
            $result[] = [
                'goodsId' => $good['goodsId'],
                'goodsHash' => $good['goodsHash'],
                'goodsContract' => $good['goodsContract'],
                'goodsStatus' => 2, //转赠中
            ];
        }

        return $this->successResponse($result, $request['method']);
    }

    /**
     * 验证转增结果.
     *
     * @param mixed $request
     */
    public function goodsTransferConfirm($request)
    {
//        $all_param = $this->getParam($request['objEncrypt']);
//
//        $agentId = $request['agent_id'];
//
//        $log = AssetGiveLog::where('tranNo', $all_param['tranNo'])->first();
//
//        if (empty($log)) {
//            return $this->failResponse(60403, '未找到该转增订单');
//        }
//
//        $param = json_decode($log['param'], true);
//
//        /** @var FrontendUser $receiveUser */
//        $receiveUser = FrontendUser::query()
//            ->where('mobile', $param['targetPhone'])
//            ->where('agent_id', $agentId)
//            ->first();
//
//        $list = [];
//        $flag = 1;
//        foreach ($param['goodsList'] as $k => $v) {
//            $asset = Asset::where('user_id', $receiveUser->id)
//                ->where('source_id', $v['goodsId'])->where('source_type', AssetSourceType::GIVE)
//                ->first();
//            $status = 1;
//            if (empty($asset)) {
//                $status = 0;
//                $flag = 0;
//            }
//
//            $list[] = [
//                'goodsId' => $v['goodsId'],
//                'goodsStatus' => $status,
//            ];
//        }
//
//        return $this->successResponse(['status' => $flag, 'tranNo' => $all_param['tranNo'], 'goodsList' => $list], $request['method']);
    }

    /**
     * XMeta向一级平台发起上架下架藏品
     *
     * @param mixed $request
     */
    public function goodsLock($request)
    {
        $param = $this->getParam($request['objEncrypt']);

        $agentId = $request['agent_id'];

        $user = FrontendUser::where('wallet_address', 'like', '%' . $param['walletHash'] . '%')
            ->where('agent_id', $agentId)->first();

        $list = [];
        foreach ($param['goodsList'] as $k => $v) {
            $asset = Asset::where('user_id', $user->id)
                ->where('id', $v['goodsId'])
                ->where('trans_hash', $v['goodsHash'])
                ->first();

            if (empty($asset)) {
                if (0 == $v['status']) {
                    $asset->asset_status = AssetStatus::HOLD;
                } else {
                    $product = Product::query()
                        ->where('agent_id', $agentId)
                        ->where('contract_address', $asset)
                        ->first();
                    if (!$product) {
                        return $this->failResponse(1003, '商品未找到');
                    }
                    $isLocked = $product->configs()
                        ->where('config_key', ProductConfig::IS_LOCKED)
                        ->value('config_value');
                    if (!$isLocked) {
                        return $this->failResponse(1004, '商品未锁定，无法上架到交易所');
                    }
                    $asset->asset_status = AssetStatus::ON_SALE;
                }

                $asset->save();
            }

            $list[] = [
                'goodsId' => $v['goodsId'],
                'status' => 1,
            ];
        }

        return $this->successResponse(['walletHash' => $param['walletHash'], 'goodsList' => $list], $request['method']);
    }

    /**
     * XMeta向一级平台获取藏品档案下未锁定藏品数量.
     *
     * @param mixed $request
     */
    public function goodsCount($request)
    {
        $param = $this->getParam($request['objEncrypt']);

        $agentId = $request['agent_id'];

        if (empty($param['phone'])) {
            return $this->failResponse(50200, '缺少必要参数');
        }

        $user = FrontendUser::where('mobile', $param['phone'])
            ->where('agent_id', $agentId)->first();

        $query = $this->getMyAssetQuery($user);

        $assetProducts = $query
            ->select([
                'contract_address',
                DB::raw('max(id) as max_id'),
                DB::raw('count(*) as token_count'),
            ])->groupBy('contract_address')
            ->orderByDesc('max_id')
            ->get();

        $products = Product::query()
            ->with(['category'])
            ->whereIn('contract_address', Arr::pluck($assetProducts, 'contract_address'))
            ->where('type', ProductType::ISSUE)
            ->get()->mapWithKeys(function (Product $product) {
                return [$product->contract_address => $product];
            });

        $list = [];
        foreach ($assetProducts as $item) {
            /** @var Product $product */
            $product = Arr::get($products, $item->contract_address);
            if ($product) {
                $list[] = [
                    'archiveId' => $product->id,
                    'count' => $item->token_count,
                ];
            }
        }

        return $this->successResponse(['archiveList' => $list], $request['method']);
    }

    public function successResponse($data, $method)
    {
        $response = [
            'appId' => $this->app_id,
            'method' => $method,
            'code' => 20000,
            'msg' => '获取成功',
            'timestamp' => time() * 1000,
            'nonce' => md5(uniqid(microtime(true), true)),
            'version' => '1.2.0',
            'objEncrypt' => $this->AESEncrypt(json_encode($data), $this->aeskey),
        ];

        $response['sign'] = $this->sign($response);

        return $response;
    }

    public function getParam($param)
    {
        return json_decode($this->AESDecrypt($param, $this->aeskey), true);
    }

    /**
     * 上传藏品
     */
    public function syncGoods()
    {
        Factory::setOptions($this->getOptions());

        $goods_id = request()->goods_id;

        $product = Product::find($goods_id);

        $appSecret = $this->aeskey;
        $appId = $this->app_id;
        $data = [
            'appId' => $appId,
            'timestamp' => time() * 1000,
            'nonce' => md5(uniqid(microtime(true), true)),
            'method' => 'xmeta.mall.archive.goods.transfer',
            'version' => '1.2.0',
        ];
        $bizData = [
            'archiveList' => [
                [
                    'archiveId' => $product->id,
                    'publishCount' => $product->sales_count,
                    'archiveImage' => $product->logo_url,
                    'archiveName' => $product->name,
                    'issueTime' => $product->created_at->toArray()['formatted'],
                    'archiveDescription' => $product->description,
                    'seriesTitle' => $product->name,
                ],
            ],
        ];

        $data['objEncrypt'] = $this->AESEncrypt(json_encode($bizData));
        $sign = $this->sign($data);
        $data['sign'] = $sign;
        // 将请求发送至盯链网关，验证无误返回用户token
        // 以下仅为示例，请更换为您自己的请求库
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => 'https://dev-open-api.x-metash.com/gateway/forward/',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => json_encode($data),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
            ],
        ]);
        $response = curl_exec($curl);
        curl_close($curl);

        $res = json_decode($response, true);

        if (20000 == $res['code']) {
            echo 'success';
        }
        echo 'fail';
    }

    public function failResponse($code, $msg)
    {
        $response = [
            'appId' => $this->app_id,
            'method' => $this->method,
            'code' => $code,
            'msg' => $msg,
            'timestamp' => time() * 1000,
            'nonce' => md5(uniqid(microtime(true), true)),
            'version' => '1.2.0',
            'objEncrypt' => Factory::util()->aes()->encrypt(json_encode([])),
        ];

        $response['sign'] = $this->sign($response);

        return $response;
    }

    public function getOptions()
    {
        $options = new Config();
        $options->protocol = 'https';
        $options->gatewayHost = 'dev-open-api.x-metash.com/gateway/forward/';
        $options->signType = 'RSA2';

        $options->appId = $this->app_id;

        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        $options->merchantPrivateKey = $this->pra_secret;

//        $options->alipayCertPath = '<-- 请填写您的支付宝公钥证书文件路径，例如：/foo/alipayCertPublicKey_RSA2.crt -->';
//        $options->alipayRootCertPath = '<-- 请填写您的支付宝根证书文件路径，例如：/foo/alipayRootCert.crt" -->';
//        $options->merchantCertPath = '<-- 请填写您的应用公钥证书文件路径，例如：/foo/appCertPublicKey_2019051064521003.crt -->';

        //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
        $options->alipayPublicKey = $this->xmeta_pub_key;

        //可设置异步通知接收服务地址（可选）
//        $options->notifyUrl = "<-- 请填写您的支付类接口异步通知接收服务地址，例如：https://www.test.com/callback -->";

        //可设置AES密钥，调用AES加解密相关接口时需要（可选）
        $options->encryptKey = $this->aeskey;

        return $options;
    }

    public function test()
    {
//        Factory::setOptions($this->getOptions());
//        $str = "1iwmtRkAyonWIE64MngE9D1ZrXCKJ62TSfGrSupgIzYfREuPTqzr2mAawjstfdmwIIa3Pt2fblbclIVVcl4Nb0yWETg2bTYhDbJjVUsckrI2qaP/LcvfLjqp1HhxTkpayVqRzhc3bGwIVS5esfzpig==";
//        dd(Factory::util()->aes()->decrypt($str));

//        $data = [
//            "sourcePhone"=>"13343391173",
//            "targetPhone"=>"13261063826",
//            "tranNo"=>"XMMALL20220708175632889132",
//            "sourceWalletHash"=>"0x3441d744731c46f6de2ed6163ac8eb8c4c4fb95c",
//            "targetWalletHash"=>"0xa6f322b9267dd4f69318f65e8380ed81a352c979",
//            "goodsList"=>[
//                [
//                    "goodsId"=>"37218",
//                    "goodsHash"=>"0x4ea9041a2b557d54a4610c3a48947c85f3e59d35d2ac097039499a003070c361",
//                    "goodsContract"=>"0x799a7383dd889569b31ee84525fb0dc5643de45c",
//                    "goodsPrice"=>"0.3",
//                    "reduceCost"=>"0.2",
//                    "rebate"=>"0.2",
//                ]
//            ],
//        ];

//        $data = [
//            'tranNo'=>'XMMALL20220708175632889132'
//        ];
//        dd(Factory::util()->aes()->encrypt(json_encode($data)));
    }

    /**
     * @param mixed $receiveUser
     * @param mixed $assetId
     *
     * @throws ApiException
     */
    private function doAssetGive(FrontendUser $user, $receiveUser, $assetId)
    {
        $lock = \Cache::lock('asset_give_' . $assetId, 5);

        /** @var Asset $asset */
        $asset = Asset::query()
            ->where('user_id', $user->id)
            ->find($assetId);
        if (!$asset) {
            return $this->failResponse(60200, '资产未找到或不可转赠');
        }
        /** @var Product $product */
        $product = Product::query()->where('contract_address', $asset->contract_address)->first();
        // 检查转赠配置
        $this->checkGiveConfig($asset, $product);

        try {
            $lock->block(1); // 如果获取不到锁，则等待2秒

            $record = new TransferRecord();
            $record->agent_id = request()->agent_id;
            $record->asset_id = $asset->id;
            $record->to_user_id = $buyer->id;
            $record->source = TransferSource::DING_BLOCK;
            $record->transfer_sn = $orderId;
            $record->source_params = json_encode($bizData);
            $record->save();
            TransferJob::dispatch($record);
        } catch (LockTimeoutException $e) {
            return 0;
        } finally {
            $lock->release();
        }

        return 1;
    }

    /**
     * AES-256-ECB（PKCS5Padding）解密，base64decoding.
     *
     * @param mixed $data
     * @param mixed $key
     */
    private function AESDecrypt($data)
    {
        return Factory::util()->aes()->decrypt($data);
//        return @openssl_decrypt(
//            base64_decode($data),
//            'AES-aeskey-CBC',
//            $key,
//            OPENSSL_RAW_DATA
//        );
    }

    /**
     * AES-256-ECB（PKCS5Padding）加密，base64encoding.
     *
     * @param mixed $data
     * @param mixed $key
     */
    private function AESEncrypt($data)
    {
        return Factory::util()->aes()->encrypt($data);
//        return @base64_encode((openssl_encrypt(
//            $data,
//            'AES-128-CBC',
//            $key,
//            OPENSSL_RAW_DATA,
//        )));
    }

    /**
     * 加签方法.
     *
     * @param mixed $data
     */
    private function sign($data)
    {
        // 组装签名字符串
        $arr = [];
        foreach ($data as $name => $value) {
            // 如果objEncrypt没有转成string
            if ('objEncrypt' == $name && !is_string($value)) {
                return;
            }
            if ('sign' != $name) {
                array_push($arr, $name . '=' . $value);
            }
        }
        sort($arr);
        $signStr = join('&', $arr);

        $search = [
            '-----BEGIN RSA PRIVATE KEY-----',
            '-----END RSA PRIVATE KEY-----',
            "\n",
            "\r",
            "\r\n",
        ];
        $private_key = str_replace($search, '', $this->pra_secret);
        $private_key = $search[0] . PHP_EOL . wordwrap($private_key, 64, "\n", true) . PHP_EOL . $search[1];

        $res = openssl_get_privatekey($private_key);
        if ($res) {
            openssl_sign($signStr, $sign, $res, OPENSSL_ALGO_SHA256);
        } else {
            return -1;
        }

        return base64_encode($sign);
    }

    private function getMyAssetQuery($user)
    {
        return Asset::where('user_id', $user->id)
            ->where('asset_status', AssetStatus::HOLD);
    }

    private function checkGiveConfig(Asset $asset, Product $product)
    {
        // 判断商品转赠配置
        $giveConfigs = $product->configs()
            ->whereIn(
                'config_key',
                [ProductConfig::GIVE_FORBID, ProductConfig::GIVE_DURATION, ProductConfig::IS_LOCKED]
            )
            ->get()
            ->mapWithKeys(function (ProductConfig $config) {
                return [$config->config_key => $config->config_value];
            });

        $giveForbid = (bool) Arr::get($giveConfigs, ProductConfig::GIVE_FORBID, false);
        $giveDuration = Arr::get($giveConfigs, ProductConfig::GIVE_DURATION, 0);
        $isLocked = (bool) Arr::get($giveConfigs, ProductConfig::IS_LOCKED, false);

        if ($isLocked) {
            throw new ApiException('资产已锁定，不可转赠');
        }
        if ($giveForbid) {
            throw new ApiException('该资产不支持转赠');
        }
        if ($giveDuration > 0 && now()->lt($asset->created_at->addDays($giveDuration))) {
            throw new ApiException("资产持有超过{$giveDuration}天后才可以转售");
        }
    }
}
